package dao;

import cn.demoncat.util.es.dao.BaseEsDao;
import cn.demoncat.util.es.util.QueryBuilderUtil;
import cn.demoncat.util.es.util.QueryUtil;
import cn.demoncat.util.lang.*;
import cn.demoncat.util.lang.constant.StringConstant;
import cn.demoncat.util.lang.entity.ListObj;
import cn.demoncat.util.lang.entity.Pager;
import doc.MallItemSearchDoc;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;

/**
 * 商品搜索 - ES
 *
 * @author 延晓磊
 * @since 2021年01月19日
 */
@Component
public class MallItemSearchDao extends BaseEsDao<MallItemSearchDoc,Long> {

    /**
     * 建议列表
     * 
     * @param kw    关键词：标题、分类、品牌
     * @return
     * 
     * @author 延晓磊
     * @since 2021年01月19日
     */
    public List<String> suggest(String kw){
        return this.completionSuggest(kw, "suggest");
    }

    /**
     * 商品列表
     *
     * 1、选择分类时，前端拉取分类的属性和品牌，渲染商品搜索的筛选项
     * 2、未选分类时，京东会聚合所有关联商品的分类、属性、品牌，但效果杂乱不采用，前端只需把搜索结果的分类去重后列出来，让用户去选择分类
     *
     * @param kw            关键词：标题、分类、地址、品牌
     * @param catId         分类ID，前缀匹配
     * @param areaId        地址ID，前缀匹配
     * @param brandId       品牌ID，多个用,分隔（支持多选）
     * @param attrs         商品属性：attrId + val，多个用,分隔（支持多选）
     * @param price         价格：0-10 || 10以上 , 10 , 10- || 10以下 , -10
     * @param sort          排序方式：30/31首次上架时间，40/41价格，50/51库存，60/61销量
     * @param pageNum
     * @param pageSize
     *
     * @author 延晓磊
     * @since 2021年01月19日
     */
    public Pager<MallItemSearchDoc> findPage(String kw, String catId, String areaId, String brandId, String attrs, String price, String sort, Integer pageNum, Integer pageSize){
        // 排序方式
        Sort sorts = null;
        if (StringUtils.isNotBlank(sort)) {
            switch (sort) {
                case "30":
                    sorts = QueryUtil.getSort("putTime");
                    break;
                case "31":
                    sorts = QueryUtil.getSort("putTime", false);
                    break;
                case "40":
                    sorts = QueryUtil.getSort("price");
                    break;
                case "41":
                    sorts = QueryUtil.getSort("price", false);
                    break;
                case "50":
                    sorts = QueryUtil.getSort("num");
                    break;
                case "51":
                    sorts = QueryUtil.getSort("num", false);
                    break;
                case "60":
                    sorts = QueryUtil.getSort("sellNum");
                    break;
                case "61":
                    sorts = QueryUtil.getSort("sellNum", false);
                    break;
                default:
                    break;
            }
        }

        // 搜索条件 - 计分
        List<QueryBuilder> queries = new ArrayList<>();
        if (StringUtils.isNotBlank(kw)) {
            // 关键词
            queries.add(QueryBuilderUtil.match("content", kw));
        }
        QueryBuilder query = queries.isEmpty() ? null : queries.get(0);

        // 过滤条件 - 不计分
        List<QueryBuilder> filters = new ArrayList<>();
        if (StringUtils.isNotBlank(catId)) {
            // 分类：前缀查询
            filters.add(QueryBuilderUtil.prefix("catId",catId));
        }
        if (StringUtils.isNotBlank(areaId)) {
            // 地址：前缀查询
            filters.add(QueryBuilderUtil.prefix("areaId", AreaUtil.trim(areaId)));
        }
        if (StringUtils.isNotBlank(brandId)) {
            // 品牌：多值匹配
            filters.add(QueryBuilderUtil.terms("brandId", ArrayUtil.toObjArray(StringUtil.split(brandId))));
        }
        if (StringUtils.isNotBlank(attrs)) {
            // 属性：单个属性in查询，多个属性and查询
            Map<String, ListObj> attrMap = new HashMap<>();
            for (String attr : StringUtil.splitToSet(attrs)){
                MapUtil.get(attrMap, attr.substring(0,3), new ListObj()).add(attr);
            }
            for (ListObj list : attrMap.values()) {
                // 数组查询：单值 = term，多值 = 多次term
                if (list.size() == 1) {
                    filters.add(QueryBuilderUtil.term("attrs", list.get(0)));
                }else{
                    filters.add(QueryBuilderUtil.terms("attrs", list.toArr()));
                }
            }
        }
        if (StringUtils.isNotBlank(price)) {
            // 价格：0-10 || 10以上 , 10- , 10 || 10以下 , -10
            price = StringUtil.remove(price);
            BigDecimal min = BigDecimal.ZERO;
            BigDecimal max = BigDecimal.valueOf(Integer.MAX_VALUE);
            // 规范输入参数：10- || -10 || 0-10
            if (price.endsWith("以上")) {
                // 10以上 = 10-
                price = StringUtils.substring(price, 0, -2) + StringConstant.BAR;
            }else if (price.endsWith("以下")) {
                // 10以下 = -10
                price = StringConstant.BAR + StringUtils.substring(price, 0, -2);
            }else if (!price.contains(StringConstant.BAR)) {
                // 10 = 10-
                price = price + StringConstant.BAR;
            }
            // 整合输入条件
            if (price.endsWith(StringConstant.BAR)) {
                // 10- = 10 > MAX
                min = DecimalUtil.valueOfZero(price.substring(0, price.length()-1));
            }else if (price.startsWith(StringConstant.BAR)) {
                // -10 = 0 > 10
                max = DecimalUtil.valueOfZero(price.substring(1));
            }else{
                // 0-10
                String[] ms = price.split(StringConstant.BAR);
                min = DecimalUtil.valueOfZero(ms[0]);
                max = DecimalUtil.valueOfZero(ms[1]);
            }
            filters.add(QueryBuilderUtil.between("price", min, max));
        }
        QueryBuilder filter = filters.isEmpty() ? null : QueryBuilderUtil.and(filters);

        // 整合查询
        return this.findPage(QueryUtil.build(query, filter), pageNum, pageSize, sorts);
    }

    /**
     * 商品列表
     *
     * @param ids   商品ID列表，多个用,分隔：非空时根据id搜索商品，以传参id排序；限100个内
     * @return
     *
     * @author 延晓磊
     * @since 2021年01月26日
     */
    public List<MallItemSearchDoc> findList(String ids){
        // 搜索
        String[] idArr = StringUtil.split(ids);
        List<MallItemSearchDoc> list = this.findAll(QueryUtil.ids(idArr));
        // 排序
        Map<String,Integer> idSort = new HashMap<>(idArr.length);
        for (int i = 0; i < idArr.length; i++) {
            idSort.put(idArr[i],i);
        }
        list.sort(Comparator.comparing(a -> idSort.get(a.getId().toString())));
        return list;
    }

}
